iT邦幫忙

1

覺得 git filter-branch 很難用?試試看 git filter-repo!一個指令從 git history 移除特定檔案

  • 分享至 

  • xImage
  •  

在開發過程中,我們有時會不小心將不該加入 Git 的檔案 commit 進 repo,例如:

  • 含有敏感資訊的設定檔(如 API 金鑰、帳密)
  • 執行檔或外部套件(如 .terraform/ 目錄下的 provider binary)
  • 中間產物、快取檔、工作目錄

即使後來在 .gitignore 排除了這些檔案,它們仍然會殘留在 Git 的歷史紀錄。這時候我們可以使用 git filter-repo 來重寫整個 Git history,從歷史紀錄中徹底移除這些資料。

git filter-repo 簡介

git filter-repo官方推薦的 Python 開源工具,可以用來:

  • 刪除歷史中的檔案(包括敏感資訊)
  • 修改 commit 作者資訊
  • 調整資料夾結構

git filter-repo 的特點是:

  • 快速(比 filter-branch 快非常多)
  • 彈性高(支援多種規則)
  • 易於使用,單一指令即可操作

為什麼是 git filter-repo

目前常見的 Git 歷史重寫工具如下:

工具 優點 缺點
git filter-branch 內建、可自訂 shell script 非常慢、語法繁瑣、容易出錯
git filter-repo 快速、安全、彈性高 需額外安裝
BFG Repo-Cleaner 操作簡單、速度快 無法細緻控制特定檔案/作者

✅ 在 git filter-branch 官方手冊的 WARNING 中,指出其性能與安全上的問題,並推薦使用 git filter-repo 取代。


安裝 git filter-repo

macOS

brew install git-filter-repo

Ubuntu/Debian

sudo apt install git-filter-repo

跨平台(使用 pip)

pip install git-filter-repo

✅ 安裝成功測試

git filter-repo --analyze

安裝失敗的替代方案

如果你不幸安裝失敗(像我一樣 😭),這裡提供不安裝的替代方案:

  1. 下載 git-filter-repo
  2. git-filter-repo(沒有副檔名)放入 Git 安裝路徑。
    • 例如:C:\Program Files\Git\mingw64\libexec\git-core
  3. 若出現「Python was not found」錯誤,請修改 git-filter-repo 的第一行(Shebang line),手動指定你的 python.exe 路徑:
    #!C:\Python311\python.exe
    

使用 git filter-repo 移除指定檔案

⚠️使用這個工具會重寫 Git history,所以執行前記得先備份!

基本語法

git filter-repo --path <path> --invert-paths
  • --path: 指定要移除的檔案或資料夾。
  • --invert-paths: 表示保留其他內容、移除指定的 path。

指令範例

# 移除 `key.json`(不包含子目錄底下的同名檔案)
git filter-repo --path key.json --invert-paths --force

# 移除 `keys/` 資料夾下的所有檔案。
git filter-repo --path keys/ --invert-paths

# 移除與 glob 相符的檔案。
git filter-repo --path-glob */logs/ --invert-paths

# 移除與 RegEx 相符的檔案。
git filter-repo --path-regex .*/logs/application.[0-9]+.log --invert-paths

# 移除所有路徑底下的 `.DS_Store` 檔案。
git filter-repo --path .DS_Store --use-base-name --invert-paths

在官方文件的說明中,提到可以使用單引號包住 <path>,但是我自己用的時候,如果有加單引號就會 match 失敗。
因此實際使用前,建議建立一個測試用的 Git Repo,確認如何下指令可以達成你想要的效果哦!

推送修改後的新歷史

# 更新 remote URL
git remote set-url origin <remote-repo-url>

# 強制推送新的 history
git push --force --all

實際使用效果示範

前置作業

  1. 建立測試用的 Git Repo:
    git init
    
  2. 加入含有敏感資料的檔案:
    echo secrets > key.json
    git add *
    git commit -m "feat: add key.json"
    
  3. 加入幾個檔案,模擬正常開發流程:
    echo hello > file1.txt
    git add *
    git commit -m "feat: add file1"
    
    echo hello > file2.txt
    git add *
    git commit -m "feat: add file2"
    
  4. 加入 Log 檔案,模擬誤將工作目錄 commit 到 git:
    mkdir logs
    echo hello > logs\app.0.log
    echo hello > logs\app.1.log
    git add *
    git commit -m "feat: add logs"
    

執行指令前

  • 檔案目錄:
    > git ls-files
    file1.txt
    file2.txt
    key.json
    logs/app.0.log
    logs/app.1.log
    
  • history:
    > git log --oneline
    bf4d019 (HEAD -> main) feat: add logs
    f6242d9 feat: add file2
    2d8d990 feat: add file1
    a1e210b feat: add key.json
    

從 git history 移除指定檔案

  1. 移除 key.json
    git filter-repo --path key.json --invert-paths --force
    
  2. 移除所有副檔名為 .log 的檔案。
    git filter-repo --path-glob **/*.log --invert-paths
    

執行指令後

  • 檔案目錄:
    > git ls-files
    file1.txt
    file2.txt
    
  • history:
    > git log --oneline
    2bf3da8 (HEAD -> main) feat: add file2
    a56e671 feat: add file1
    

參考資料


尾聲

最近公司從 Gitea 移轉到 GitHub,有改寫 git history 的需求,發現中文圈有很多 git-filter-branch 的文章,但關於 git-filter-repo 這個工具的文章不多,尤其是 Windows 安裝失敗的排除方式……

因此花了一點時間撰寫這篇文章,希望能給大家帶來一些幫助 :D


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言